fix(gke): resolve version aliases on UpdateCluster desired versions - #198
Conversation
desiredMasterVersion and desiredNodeVersion were stored verbatim, so gcloud `container clusters upgrade` with no --cluster-version, which sends the literal "-", left the cluster reporting version "-". Route desiredMasterVersion through the resolver UpdateMaster already uses and resolve desiredNodeVersion the same way, except that "-" on the node side picks the cluster's current master version, as the proto documents. Closes floci-io#196
|
| Filename | Overview |
|---|---|
| src/main/java/io/floci/gcp/services/gke/GkeService.java | Resolves UpdateCluster master and node aliases before updating cluster and node-pool state. |
| src/test/java/io/floci/gcp/services/gke/GkeServiceTest.java | Adds focused coverage for master aliases, node aliases, explicit versions, and independent control-plane and node versions. |
| src/test/java/io/floci/gcp/services/gke/GkeUpdateClusterRestIntegrationTest.java | Verifies the gcloud-style REST request bodies produce concrete master and node versions. |
| docs/services/gke.md | Documents UpdateCluster alias behavior and the node-side meaning of -. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[UpdateCluster request] --> B{Version field}
B -->|desiredMasterVersion| C[resolveMasterVersion]
C --> D[Update currentMasterVersion]
B -->|desiredNodeVersion| E{Requested value is dash?}
E -->|Yes| F[Use current master version]
E -->|No| G[resolveMasterVersion]
F --> H[Update cluster node version]
G --> H
H --> I[Update targeted node pools]
Reviews (1): Last reviewed commit: "fix(gke): resolve version aliases on Upd..." | Re-trigger Greptile
|
Thank you, and particularly for checking the one-field-per-request rule rather than assuming it, since the whole design rests on it. I confirmed all three:
No blockers from my side. |
hectorvent
left a comment
There was a problem hiding this comment.
All three contract claims confirmed verbatim, including the one-field-per-request rule the design rests on; tests 49/0 locally.
|
Happy to. Both landed, so it is its own PR: #199 passes the field name into the resolver, and |
|
🎉 This PR is included in version 0.9.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
# [0.9.0](floci-io/floci-gcp@0.8.0...0.9.0) (2026-09-15) ### Bug Fixes * **firebaseauth:** match Number() coercion for session cookie validDuration ([floci-io#154](floci-io#154)) ([c71702c](floci-io@c71702c)), closes [Number#longValue](https://github.com/Number/issues/longValue) * **firebaseauth:** send CORS headers on Identity Toolkit client endpoints ([floci-io#153](floci-io#153)) ([8855603](floci-io@8855603)) * **firebaseauth:** send CORS headers on the emulator endpoints and always vary on Origin ([floci-io#186](floci-io#186)) ([ca81461](floci-io@ca81461)) * **gcs:** batch requests fail when the published port differs from the internal one ([floci-io#167](floci-io#167)) ([d810602](floci-io@d810602)) * **gcs:** evict abandoned resumable and streaming upload sessions ([floci-io#176](floci-io#176)) ([6033f0c](floci-io@6033f0c)), closes [floci-io#136](floci-io#136) [floci-io#150](floci-io#150) * **gcs:** map cacheControl and customTime on the gRPC object path ([floci-io#184](floci-io#184)) ([e94d179](floci-io@e94d179)) * **gcs:** populate Bucket.bucket_id on gRPC bucket responses ([floci-io#155](floci-io#155)) ([5611bff](floci-io@5611bff)), closes [floci-io#148](floci-io#148) * **gcs:** preserve prefixes when listing with matchGlob ([floci-io#188](floci-io#188)) ([4846129](floci-io@4846129)) * **gcs:** reject deletion of non-empty buckets ([floci-io#180](floci-io#180)) ([0ec3a3e](floci-io@0ec3a3e)), closes [floci-io#178](floci-io#178) * **gcs:** resolve the request base URL from the authority, not the Host header ([floci-io#168](floci-io#168)) ([285d04d](floci-io@285d04d)) * **gke:** reject master version spellings the field does not document ([floci-io#197](floci-io#197)) ([7939306](floci-io@7939306)), closes [floci-io#195](floci-io#195) * **gke:** resolve version aliases on UpdateCluster desired versions ([floci-io#198](floci-io#198)) ([1bd6583](floci-io@1bd6583)), closes [floci-io#196](floci-io#196) ### Features * **gcs:** accept system metadata at upload time and allow zero-byte objects ([floci-io#170](floci-io#170)) ([8c480a2](floci-io@8c480a2)) * **gcs:** add chunked rewrite, HMAC keys, and soft delete with restore ([floci-io#175](floci-io#175)) ([048333e](floci-io@048333e)) * **gcs:** add endOffset, matchGlob and includeTrailingDelimiter to objects.list ([floci-io#169](floci-io#169)) ([4891e75](floci-io@4891e75)) * **gcs:** add projects.serviceAccount and the GCS testIamPermissions spelling ([floci-io#171](floci-io#171)) ([6e524bf](floci-io@6e524bf)), closes [Storage#getServiceAccount](https://github.com/Storage/issues/getServiceAccount) [storage#testIamPermissionsResponse](https://github.com/storage/issues/testIamPermissionsResponse) * **gcs:** honour conditional read preconditions on objects.get ([floci-io#172](floci-io#172)) ([707cc4f](floci-io@707cc4f)) * **gcs:** serve decompressive transcoding and add XML list and delete ([floci-io#173](floci-io#173)) ([649e9fc](floci-io@649e9fc)) * **gcs:** validate bucket names and tighten bucket and compose error shapes ([floci-io#174](floci-io#174)) ([0310ea2](floci-io@0310ea2)) * **gke:** implement ClusterManager.UpdateMaster ([floci-io#192](floci-io#192)) ([c534f6b](floci-io@c534f6b)), closes [floci-io#177](floci-io#177) * **gke:** model node pools as real resources and complete the ClusterManager surface ([floci-io#96](floci-io#96)) ([20c1fd9](floci-io@20c1fd9)), closes [floci-io#95](floci-io#95) ### Performance Improvements * **docker:** move the runtime images to ubi9-micro and drop gosu ([floci-io#185](floci-io#185)) ([c9c2f97](floci-io@c9c2f97)), closes [#3037](https://github.com/floci-io/floci-gcp/issues/3037) [#3085](https://github.com/floci-io/floci-gcp/issues/3085) [#3108](https://github.com/floci-io/floci-gcp/issues/3108)
Summary
UpdateClusterstoreddesiredMasterVersionanddesiredNodeVersionverbatim. Both fields document the same aliases asUpdateMasterRequest.master_version(latest,-,1.X,1.X.Y), and gcloud relies on them:gcloud container clusters upgrade C --masterand... --node-pool Pboth callUpdateCluster, and when no--cluster-versionis given gcloud sends the literal-(api_adapter.py,UpdateClusterCommon). Against the emulator the cluster then reportedcurrentMasterVersion: "-". Closes #196.This is the gap noted in #192, where
UpdateMastergained alias resolution andUpdateClusterwas deliberately left for its own PR.What changed
desiredMasterVersiongoes through the existingresolveMasterVersion, so it behaves exactly likeUpdateMaster.desiredNodeVersiongoes through a new one-lineresolveNodeVersion: identical rules, except-picks the cluster's current master version rather than the server default, which is the one documented difference between the two fields (cluster_service.protoL3542: "picks the Kubernetes master version"). The resolved value is applied to both the cluster aggregate and each targeted pool.updateClusteris unchanged: the node block still resolves its targets before mutating anything, so a rejecteddesiredNodePoolIdleaves no partial state. The proto allows oneClusterUpdatefield per request, so a node-reads the stored master version, not one the same request might also be changing.docs/services/gke.mdupdated.Independent of #195 (different lines of the same file); either can merge first.
Type of change
fix:)feat:)feat!:orfix!:)GCP Compatibility
Alias semantics from
ClusterUpdate.desired_master_version(L3706-L3716) anddesired_node_version(L3532-L3543) incluster_service.proto@aa87617d67. Request shapes in the REST test are the ones gcloud sends forcontainer clusters upgradewith and without--master.Tests
GkeServiceTest.updateClusterResolvesDesiredMasterVersionAliases(new):-andlatestresolve to the advertised version; explicit stays verbatim; node version does not move.GkeServiceTest.updateClusterResolvesDesiredNodeVersionAliasesAgainstTheMaster(new): on a cluster whose master is not the advertised version, nodelatestresolves to the advertised version and node-resolves to the cluster's master, on both the aggregate and the pool.GkeUpdateClusterRestIntegrationTest(new): the two gcloud request bodies overPUT, asserting the read-back is a real version and never-.but was: <->/but was: <latest>.Full suite: baseline on
main@c534f6bis 1043 run / 0 failures / 0 errors / 0 skipped; with this change 1046 / 0 / 0 / 0 (the 3 new tests, nothing else changed).Checklist
./mvnw testpasses locally🤖 Generated with Claude Code
https://claude.ai/code/session_01VTYz9WSVDx9vDqBoy4K96j